#include "guish.hpp"

static string parseVarname(string cmd, size_t &offset);

ShellState::ShellState()
{
	this->isInteractive = true;
	this->lastReturnCode = 0;
}

ShellState::ShellState(const ShellState &copy)
	:env(copy.env), aliases(copy.aliases)
{
	this->isInteractive = copy.isInteractive;
	this->lastReturnCode = copy.lastReturnCode;
}

string ShellState::envExpand(string str)
{
	vector<char> tags = tagString(str);
	string ret = "";
	
	for(size_t ii=0; ii<str.length(); ii++)
	{
		if(str[ii]=='$' && (tags[ii]==tagUnquoted || tags[ii]==tagDoubleQuoted))
		{
			string varname = parseVarname(str, ii);
			if(varname=="") {
				ret+="$";
			} else if(varname=="?") {
				char buf[16];
				sprintf(buf, "%i", lastReturnCode);
				ret += buf;
			} else {
				ret += env.get(varname);
			}
		}
		else
		{
			ret += str[ii];
		}
	}
	
	return ret;
}

string ShellState::pathLookup(string str)
{
	const char pathSeparator = ':';
	string path = env.get("PATH");
	size_t start=0;
	
	for(size_t pos=0; pos<path.length(); pos++)
	{
		if(path[pos]==pathSeparator) {
			string pathentry = path.substr(start, pos-start);
			start = pos+1;
			
			string pathname = pathentry + "/" + str;
			if(!access(pathname.c_str(), X_OK))
				return pathname;
		}
	}
	
	string pathentry = path.substr(start, str.length()-start);
	string pathname = pathentry + "/" + str;
	if(!access(pathname.c_str(), X_OK))
		return pathname;
	
	return str;
}

//////////////////////////////////////////////////////////////////////////////

string parseVarname(string cmd, size_t &offset)
{
	if(offset+1>=cmd.length() || cmd[offset] != '$')
		return "";
	offset++;
	
	if(cmd[offset]=='{') {
		offset++;
		string ret="";
		for(; offset<cmd.length(); offset++) {
			ret += cmd[offset];
			if(cmd[offset]=='}')
				break;
		}
		return ret;
	}
	else
	{
		string ret="";
		if(isalnum(cmd[offset]) || cmd[offset]=='_' || (unsigned char)cmd[offset]>127)
		{
			for(; offset<cmd.length(); offset++) {
				unsigned char ch = cmd[offset];
				if(isalnum(ch) || ch=='_' || ch>127) {
					ret += ch;
				} else {
					offset--;
					break;
				}
			}
		}
		else
		{
			ret += cmd[offset++];
		}
		
		return ret;
	}
}

